﻿#pragma once

#include "common.h"

namespace anip
{
	enum class ColorFormat
	{
		Default = 0x1908, // GL_RGBA,
		Red = 0x1903, // GL_RED,
		RGB = 0x1907, // GL_RGB,
		RGBA = 0x1908, // GL_RGBA,
		BGR = 0x80e0, // GL_BGR,
		BGRA = 0x80e1, // GL_BGRA
	};

	enum class PrecisionType
	{
		Default = 1,
		UnsignedByte = 1,
		Float32
	};

	struct TextureOptions
	{
		enum class Wrapping
		{
			Default = 0x812f, // GL_CLAMP_TO_EDGE,
			ClampToEdge = 0x812f, // GL_CLAMP_TO_EDGE,
			ClampToBorder = 0x812d, // GL_CLAMP_TO_BORDER,
			MirroredRepeat = 0x8370, // GL_MIRRORED_REPEAT,
			Repeat = 0x2901, // GL_REPEAT,
		};

		enum class Filter
		{
			Default = 0x2601, // GL_LINEAR,
			Nearest = 0x2600, // GL_NEAREST,
			Linear = 0x2601, // GL_LINEAR
		};
		
		Wrapping wrap_s = Wrapping::Default;
		Wrapping wrap_t = Wrapping::Default;
		Filter min_filter = Filter::Default;
		Filter mag_filter = Filter::Default;
		ColorFormat format = ColorFormat::Default;
		PrecisionType precision = PrecisionType::Default;
		bool flip_y = false;
	};

	class Texture2D : public GLObject
	{
	private:
		int _width = 0, 
			_height = 0, 
			_channels = 0;

		ColorFormat _format = ColorFormat::Default;
		PrecisionType _precision = PrecisionType::Default;

		unsigned int 
			_htex = 0,
			_targetType = 0,
			_internalFormat = 0, 
			_type = 0;
		void processOptions(const TextureOptions* options, const void* data);
		Texture2D(int unused) {}

	public:
		Texture2D(int w, int h, const TextureOptions* options = nullptr);
		Texture2D(const TextureOptions* options = nullptr);
		Texture2D(const Texture2D& obj) = delete;

		static Texture2D* createFromData(
			int w, int h, const void* data, const TextureOptions* options = nullptr);
		
		// using STB library
		// supported formats: JPEG, PNG, BMP, TGA, PSD
		static Texture2D* createFromFile(string path, const TextureOptions* options = nullptr);

		static Texture2D* createMultisample(int w, int h, int samples);

		int width() const { return _width; }
		int height() const { return _height; }
		vec2 size() const { return { (float)_width, (float)_height }; }
		unsigned int id() const override { return _htex; }
		ColorFormat format() const { return _format; }
		bool isMultisample() const { return _type == 0x9100; /*GL_TEXTURE_2D_MULTISAMPLE*/ }

		unsigned char* getData(ColorFormat format = ColorFormat::Default) const;
		unsigned char* getData(ColorFormat format, size_t& size) const;

		// You must provide (width * height * channels) bytes of allocated space
		void getData(void* buf, ColorFormat format = ColorFormat::Default) const;

		void setData(const void* data);
		void setData(int w, int h, const void* data);
		bool setPartialData(int x, int y, int w, int h, const void* data);

		//void saveImage(string path) const;

		void use(int i = -1) const;
		void finalize() override;
	};
}